/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.mobiwebinc.compconn.screen;

import com.mobiwebinc.compconn.configuration.ClientConfiguration;
import com.mobiwebinc.compconn.configuration.ServerConfiguration;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Rectangle;

/**
 *
 * @author suraj
 */
public class ScreenGeometry {

    /**
     * @return the GAP
     */
    public static Point getGAP() {
        return GAP;
    }

    /**
     * @param aGAP the GAP to set
     */
    public static void setGAP(Point aGAP) {
        GAP = aGAP;
    }
    private ClientConfiguration clientConfiguration;
    private Rectangle screenRect;
    private Rectangle phoneRect;
    private Rectangle phoneInScreenRect;
    private Point phonePt;
    private Point screenPt;
    private double zoomX,  zoomY;
    private static Point GAP = new Point(0, 0);
    private Point phoneInScreenCenter;
    private int monitor;
    private double MIN_ZOOM_X = 0.25,  MIN_ZOOM_Y = 0.25,  MAX_ZOOM_X = 4,  MAX_ZOOM_Y = 4;

    public ScreenGeometry(ClientConfiguration clientConfiguration) {
        this.clientConfiguration = clientConfiguration;
        screenPt = new Point();
        phonePt = new Point();
        zoomX = zoomY = 0;
        phoneRect = new Rectangle(clientConfiguration.getScreenRect());
        phoneInScreenRect = new Rectangle();
        phoneInScreenCenter = new Point();
        resetView();
    }

    /**
     * @return the screenRect
     */
    public Rectangle getScreenRect() {
        return screenRect;
    }

    /**
     * @param screenRect the screenRect to set
     */
    public void setScreenRect(Rectangle screenRect) {
        this.screenRect = screenRect;
    }

    /**
     * @return the phoneRect
     */
    public Rectangle getPhoneRect() {
        return phoneRect;
    }

    /**
     * @param phoneRect the phoneRect to set
     */
    public void setPhoneRect(Rectangle phoneRect) {
        this.phoneRect = phoneRect;
    }

    /**
     * @return the phoneInScreenRect
     */
    public Rectangle getPhoneInScreenRect() {
        Rectangle rect = new Rectangle(phoneInScreenRect);
//        System.out.println(String.format("%d %d %d %d", phoneInScreenRect.x, phoneInScreenRect.y, phoneInScreenRect.width, phoneInScreenRect.height));
        rect.x -= screenRect.x;
        rect.y -= screenRect.y;
        return rect;
    }

    /**
     * @param phoneInScreenRect the phoneInScreenRect to set
     */
    public void setPhoneInScreenRect(Rectangle phoneInScreenRect) {
        this.phoneInScreenRect = phoneInScreenRect;
    }

    /**
     * @return the phonePt
     */
    public Point getPhonePt() {
        phonePt = translateToPhonePoint(getScreenPt());
        return phonePt;
    }

    /**
     * @param phonePt the phonePt to set
     */
    public void setPhonePt(Point phonePt) {
        this.phonePt = phonePt;
        this.screenPt = translatePoint(phonePt);
    }

    /**
     * @return the screenPt
     */
    public Point getScreenPt() {
        return screenPt;
    }

    /**
     * @param screenPt the screenPt to set
     */
    public void setScreenPt(Point screenPt) {
        this.screenPt = screenPt;
    }

    public void moveScreenPt(Point pt) {
        if(MouseInfo.getPointerInfo() != null)
            this.screenPt = MouseInfo.getPointerInfo().getLocation();
        this.screenPt.translate(pt.x, pt.y);
    }

    /**
     * @param zoom the zoom to set
     */
    public void setZoom(double x, double y, double factor) {
        setPhoneInScreenCenter(new Point((int)x,(int)y));
        setZoom(factor);
        alignPhoneScreen();
    }

    public void setZoom(double factor) {
        double factorX = factor*(MAX_ZOOM_X - MIN_ZOOM_X), factorY = factor*(MAX_ZOOM_Y - MIN_ZOOM_Y);
//        System.out.println("X " + factorX + " Y " + factorY + " lvl " + clientConfiguration.getZoomLevel() + " factor " + factor + " zoomer: " + (MAX_ZOOM_X - MIN_ZOOM_X));
        setZoom(zoomX + factorX, zoomY + factorY);
    }

    public void setZoom(double x, double y) {
        zoomX = ((x < MIN_ZOOM_X) ? MIN_ZOOM_X : ((x > MAX_ZOOM_X) ? MAX_ZOOM_X : x));
        zoomY = ((y < MIN_ZOOM_Y) ? MIN_ZOOM_Y : ((y > MAX_ZOOM_Y) ? MAX_ZOOM_Y : y));
    }

    public void pan(Point pt) {
        if(phoneInScreenRect.getHeight() == screenRect.getHeight())
            return;
        phoneInScreenCenter.setLocation(phoneInScreenCenter.x + pt.x / zoomX, phoneInScreenCenter.y + pt.y / zoomY);
        alignPhoneScreen();
    }

    public void resetView(Point point) {
        if (phoneInScreenRect.width == screenRect.width) {
            setPhoneInScreenCenter(point);
            setZoom(MIN_ZOOM_X + (MAX_ZOOM_X - MIN_ZOOM_X) * clientConfiguration.getTapZoom(), MIN_ZOOM_Y + (MAX_ZOOM_Y - MIN_ZOOM_Y) * clientConfiguration.getTapZoom());
            alignPhoneScreen();
        } else {
            resetView();
        }
    }

    private void alignPhoneScreen() {
        phoneInScreenRect.setSize((int) (phoneRect.width / zoomX), (int) (phoneRect.height / zoomY));
        phoneInScreenRect.setLocation(getPhoneInScreenCenter().x - phoneInScreenRect.width / 2, getPhoneInScreenCenter().y - phoneInScreenRect.height / 2);
        if (phoneInScreenRect.y < screenRect.y) {
            phoneRect.y = GAP.y;
            phoneInScreenRect.y = screenRect.y;
            phoneInScreenCenter.y = screenRect.y + phoneInScreenRect.height / 2;
        } else if ((phoneInScreenRect.y + phoneInScreenRect.height) > (screenRect.height + screenRect.y)) {
            phoneRect.y = -GAP.y;
            phoneInScreenRect.y = screenRect.y + screenRect.height - phoneInScreenRect.height;
            phoneInScreenCenter.y = screenRect.y + screenRect.height - phoneInScreenRect.height / 2;
        } else {
            phoneRect.y = 0;
        }
        if (phoneInScreenRect.x < screenRect.x) {
            phoneRect.x = GAP.x;
            phoneInScreenRect.x = screenRect.x;
            phoneInScreenCenter.x = screenRect.x + phoneInScreenRect.width / 2;
        } else if ((phoneInScreenRect.x + phoneInScreenRect.width) > (screenRect.width + screenRect.x)) {
            phoneRect.x = -GAP.x;
            phoneInScreenRect.x = screenRect.x + screenRect.width - phoneInScreenRect.width;
            phoneInScreenCenter.x = screenRect.x + screenRect.width - phoneInScreenRect.width / 2;
        } else {
            phoneRect.x = 0;
        }
    }

    public void resetView() {
        screenRect = ServerConfiguration.getInstance().getScreenRect(getMonitor());
        phoneInScreenRect = new Rectangle(screenRect);
        phonePt = MouseInfo.getPointerInfo().getLocation();
        screenPt = MouseInfo.getPointerInfo().getLocation();
        phoneRect = new Rectangle(clientConfiguration.getScreenRect());
        getPhoneInScreenCenter().setLocation((screenRect.width - screenRect.x) / 2, (screenRect.height - screenRect.y) / 2);
        setZoom(phoneRect.width * 1.0 / screenRect.width, phoneRect.height * 1.0 / screenRect.height);
        MIN_ZOOM_X = zoomX;
        MIN_ZOOM_Y = zoomY;
        MAX_ZOOM_X = 2.0/zoomX;
        MAX_ZOOM_Y = 2.0/zoomY;
    }

    /**
     * @return the center
     */
    public Point getPhoneInScreenCenter() {
        return phoneInScreenCenter;
    }

    /**
     * @param center the center to set
     */
    public void setPhoneInScreenCenter(Point center) {
        this.phoneInScreenCenter.setLocation(translatePoint(center));
    }

    private Point translatePoint(Point pt) {
        double x = phoneInScreenRect.x + (pt.x - phoneRect.x) / zoomX;
        double y = phoneInScreenRect.y + (pt.y - phoneRect.y) / zoomY;
        return new Point((int) (x), (int) (y));
    }

    private Point translateToPhonePoint(Point pt) {
        double x = (pt.x - phoneInScreenRect.x)*zoomX + phoneRect.x;
        double y = (pt.y - phoneInScreenRect.y)*zoomY + phoneRect.y;
        return new Point((int) (x), (int) (y));
    }

    public ClientConfiguration getClientConfiguration() {
        return clientConfiguration;
    }

    public void switchToMonitor(int monitor) {
        this.setMonitor(monitor);
    }

    /**
     * @return the monitor
     */
    public int getMonitor() {
        return monitor;
    }

    /**
     * @param monitor the monitor to set
     */
    public void setMonitor(int monitor) {
        this.monitor = monitor;
    }
}